////////////////////////////////////////////////////////////////////////////////
/// @file     adc.c
/// @author   AE TEAM
/// @brief    THIS FILE PROVIDES ALL THE SYSTEM FUNCTIONS.
////////////////////////////////////////////////////////////////////////////////
/// @attention
///
/// THE EXISTING FIRMWARE IS ONLY FOR REFERENCE, WHICH IS DESIGNED TO PROVIDE
/// CUSTOMERS WITH CODING INFORMATION ABOUT THEIR PRODUCTS SO THEY CAN SAVE
/// TIME. THEREFORE, MINDMOTION SHALL NOT BE LIABLE FOR ANY DIRECT, INDIRECT OR
/// CONSEQUENTIAL DAMAGES ABOUT ANY CLAIMS ARISING OUT OF THE CONTENT OF SUCH
/// HARDWARE AND/OR THE USE OF THE CODING INFORMATION CONTAINED HEREIN IN
/// CONNECTION WITH PRODUCTS MADE BY CUSTOMERS.
///
/// <H2><CENTER>&COPY; COPYRIGHT MINDMOTION </CENTER></H2>
////////////////////////////////////////////////////////////////////////////////

// Define to prevent recursive inclusion
#define _ADC_C_

// Files includes
#include "adc.h"

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup MM32_Example_Layer
/// @{

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ADC
/// @{

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ADC_Exported_Constants
/// @{

/////////////////////////////////////////////////////////////////////////////////
/// @brief   configure ADC1single transform  mode
/// @param   None
/// @retval  None
/////////////////////////////////////////////////////////////////////////////////
void ADC1_SingleChannel(void)
{
    RCC->AHBENR |= RCC_AHBENR_GPIOA; //enable GPIOA clock
    RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; //enableADC1clock
    GPIOA->CRL &=  ~(GPIO_CNF_MODE_MASK << GPIO_CRL_CNF_MODE_1_Pos);
    GPIOA->CRL |= GPIO_CNF_MODE_AIN << GPIO_CRL_CNF_MODE_1_Pos;

    RCC->APB2RSTR |= RCC_APB2RSTR_ADC1RST; //ADC1reset
    RCC->APB2RSTR &= ~(RCC_APB2RSTR_ADC1RST); //reset   end

    //ADC configure soft trigger, single period mode
    //8 fractional frequency
    MODIFY_REG(ADC1->ADCFG, ADC_CFGR_PRE, ADCFG_ADCPRE_8);
    MODIFY_REG(ADC1->ADCR, \
               ADCR_ADMD_PERIOD | ADCR_ADMD_CONTINUE | ADCR_ALIGN_LEFT, \
               ADCR_ADMD_PERIOD);
    //single PERIOD mode , Data right-ALIGNED, discontinue
    //enable 3 channels
    WRITE_REG(ADC1->ANYCFG, 3);
    //Enable chan 0,4,5

    MODIFY_REG(ADC1->CHANY0, ADC1_CHANY0_SEL0, 0 << ADC1_CHANY0_SEL0_Pos);
    MODIFY_REG(ADC1->CHANY0, ADC1_CHANY0_SEL1, 4 << ADC1_CHANY0_SEL1_Pos);
    MODIFY_REG(ADC1->CHANY0, ADC1_CHANY0_SEL2, 5 << ADC1_CHANY0_SEL2_Pos);

    ADC1->ADCFG |= ADCFG_ADEN;//ADC1enable

}
////////////////////////////////////////////////////////////////////////////////
/// @brief  Enable the selected ADC channel and configure its sample time. Please
///         use this function if you want to be compatible with older versions
///         of the library.
/// @param  adc:  select the ADC peripheral.
/// @param  channel: the ADC channel to configure.
/// @param  sample_time: the ADC Channel n Sample time to configure.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void ADC_xChannelConfig(ADC_TypeDef* adc, u32 channel, u32 sample_time)    //ADCSAM_TypeDef
{


    u32 tempchan;
    sample_time = sample_time & 0xF;
    tempchan = channel;
    if(tempchan > 8) {
        tempchan = tempchan & 0xF;
        tempchan = tempchan - 8;
        adc->SMPR2 &= ~(0xF << tempchan);
        adc->SMPR2 |= (sample_time << tempchan);
    }
    else {
        adc->SMPR1 &= ~(0xF << tempchan);
        adc->SMPR1 |= (sample_time << tempchan);
    }


    adc->ADCHS &= ~(1 << channel);
    adc->ADCHS |=  (1 << channel);




}



void ADC1_AnyChanMultiChannelInit2(void)
{
    RCC->AHBENR |= RCC_AHBENR_GPIOA; //enable GPIOA clock
    RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; //enableADC1clock
    GPIOA->CRL &=  ~(GPIO_CNF_MODE_MASK << GPIO_CRL_CNF_MODE_1_Pos);
    GPIOA->CRL |= GPIO_CNF_MODE_AIN << GPIO_CRL_CNF_MODE_1_Pos;

    RCC->APB2RSTR |= RCC_APB2RSTR_ADC1RST; //ADC1reset
    RCC->APB2RSTR &= ~(RCC_APB2RSTR_ADC1RST); //reset   end

    //ADC configure soft trigger, single period mode
    //8 fractional frequency
    MODIFY_REG(ADC1->ADCFG, ADC_CFGR_PRE, ADCFG_ADCPRE_8);
    ADC_xChannelConfig(ADC1, 0, ADC_SMPR_SAMCTL_240_5 );
    ADC_xChannelConfig(ADC1, 4, ADC_SMPR_SAMCTL_240_5 );
    ADC_xChannelConfig(ADC1, 5, ADC_SMPR_SAMCTL_240_5 );
    MODIFY_REG(ADC1->ADCR, \
               ADCR_ADMD_PERIOD | ADCR_ADMD_CONTINUE | ADCR_ALIGN_LEFT, \
               ADCR_ADMD_PERIOD);
    //single PERIOD mode , Data right-ALIGNED, discontinue
    //enable 3 channels
    WRITE_REG(ADC1->ANYCFG, 3);
    //Enable chan 0,4,5

    MODIFY_REG(ADC1->CHANY0, ADC1_CHANY0_SEL0, 0 << ADC1_CHANY0_SEL0_Pos);
    MODIFY_REG(ADC1->CHANY0, ADC1_CHANY0_SEL1, 4 << ADC1_CHANY0_SEL1_Pos);
    MODIFY_REG(ADC1->CHANY0, ADC1_CHANY0_SEL2, 5 << ADC1_CHANY0_SEL2_Pos);

    ADC1->ADCFG |= ADCFG_ADEN;//ADC1enable

}
void ADC1_AnyChanMultiChannelInit(void)
{
    RCC->AHBENR |= RCC_AHBENR_GPIOA; //enable GPIOA clock
    RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; //enableADC1clock
    GPIOA->CRL &=  ~(GPIO_CNF_MODE_MASK << GPIO_CRL_CNF_MODE_0_Pos);
    GPIOA->CRL |= GPIO_CNF_MODE_AIN << GPIO_CRL_CNF_MODE_0_Pos;
    GPIOA->CRL &=  ~(GPIO_CNF_MODE_MASK << GPIO_CRL_CNF_MODE_2_Pos);
    GPIOA->CRL |= GPIO_CNF_MODE_AIN << GPIO_CRL_CNF_MODE_2_Pos;
    GPIOA->CRL &=  ~(GPIO_CNF_MODE_MASK << GPIO_CRL_CNF_MODE_5_Pos);
    GPIOA->CRL |= GPIO_CNF_MODE_AIN << GPIO_CRL_CNF_MODE_5_Pos;
    GPIOA->CRL &=  ~(GPIO_CNF_MODE_MASK << GPIO_CRL_CNF_MODE_7_Pos);
    GPIOA->CRL |= GPIO_CNF_MODE_AIN << GPIO_CRL_CNF_MODE_7_Pos;

    RCC->APB2RSTR |= RCC_APB2RSTR_ADC1RST; //ADC1reset
    RCC->APB2RSTR &= ~(RCC_APB2RSTR_ADC1RST); //reset   end

    //ADC configure soft trigger, single period mode
    //8 fractional frequency
    ADC1->ANYCR |= ADC1_CHANY_CR_MDEN;
    MODIFY_REG(ADC1->ADCFG, ADC_CFGR_PRE, ADCFG_ADCPRE_8);
    MODIFY_REG(ADC1->ADCR, \
               ADCR_ADMD_PERIOD | ADCR_ADMD_CONTINUE | ADCR_ALIGN_LEFT, \
               ADCR_ADMD_PERIOD);
    //single PERIOD mode , Data right-ALIGNED, discontinue
    //enable 3 channels
    WRITE_REG(ADC1->ANYCFG, 4);
    //Enable chan 0,2,5, 7

    MODIFY_REG(ADC1->CHANY0, ADC1_CHANY0_SEL0, 0 << ADC1_CHANY0_SEL0_Pos);
    MODIFY_REG(ADC1->CHANY0, ADC1_CHANY0_SEL1, 2 << ADC1_CHANY0_SEL1_Pos);
    MODIFY_REG(ADC1->CHANY0, ADC1_CHANY0_SEL2, 5 << ADC1_CHANY0_SEL2_Pos);
    MODIFY_REG(ADC1->CHANY0, ADC1_CHANY0_SEL3, 7 << ADC1_CHANY0_SEL3_Pos);

    ADC1->ADCFG |= ADCFG_ADEN;//ADC1enable
}

void Modidfied_AnyChanMultiChannel(void)
{
    MODIFY_REG( ADC1->CHANY0, \
                ADC1_CHANY0_SEL0 | ADC1_CHANY0_SEL1 | \
                ADC1_CHANY0_SEL2 | ADC1_CHANY0_SEL3, \
                (2 << ADC1_CHANY0_SEL0_Pos) | (0 << ADC1_CHANY0_SEL1_Pos) | \
                (7 << ADC1_CHANY0_SEL0_Pos) | (5 << ADC1_CHANY0_SEL1_Pos));
}
void Modidfied_AnyChanMultiChannelB(void)
{
    MODIFY_REG( ADC1->CHANY0, \
                ADC1_CHANY0_SEL0 | ADC1_CHANY0_SEL1 | \
                ADC1_CHANY0_SEL2 | ADC1_CHANY0_SEL3, \
                (5 << ADC1_CHANY0_SEL0_Pos) | (0 << ADC1_CHANY0_SEL1_Pos) | \
                (2 << ADC1_CHANY0_SEL0_Pos) | (7 << ADC1_CHANY0_SEL1_Pos));
}
void Modidfied_AnyChanMultiChannelbak(void)
{
    MODIFY_REG(ADC1->CHANY0, ADC1_CHANY0_SEL0, 2 << ADC1_CHANY0_SEL0_Pos);
    MODIFY_REG(ADC1->CHANY0, ADC1_CHANY0_SEL1, 0 << ADC1_CHANY0_SEL1_Pos);
    MODIFY_REG(ADC1->CHANY0, ADC1_CHANY0_SEL2, 7 << ADC1_CHANY0_SEL2_Pos);
    MODIFY_REG(ADC1->CHANY0, ADC1_CHANY0_SEL3, 5 << ADC1_CHANY0_SEL2_Pos);
}
/////////////////////////////////////////////////////////////////////////////////
/// @brief    getADC1 transform data
/// @param    None
/// @retval   None
/////////////////////////////////////////////////////////////////////////////////
u16 ADC1_SingleChannel_Get(void)
{
    u32 tempData;
    __IO u32 tempData1;
    __IO u32 tempData2;
    __IO u32 tempData3;
    u32 ChanData;
    u16 puiADData;
    u16 puiChanData;
    //ADCR deviceADSTbit enable, soft start  transform
    ADC1->ADCR |= ADC_CR_ADST;
    while(((ADC1->ADSTA ) & ADC_SR_ADIF) == 0);
    tempData = ADC1->ADDATA;
    ADC1->ADSTA |= ADC_SR_ADIF;

    while(((ADC1->ADSTA ) & ADC_SR_ADIF) == 0);
    tempData1 = ADC1->ADDATA;
    ADC1->ADSTA |= ADC_SR_ADIF;
    while(((ADC1->ADSTA ) & ADC_SR_ADIF) == 0);
    tempData2 = ADC1->ADDATA;
    ADC1->ADSTA |= ADC_SR_ADIF;
    while(((ADC1->ADSTA ) & ADC_SR_ADIF) == 0);
    tempData3 = ADC1->ADDATA;
    ADC1->ADSTA |= ADC_SR_ADIF;


    ChanData =  (*(vu32*) ((u32)ADC1 + 0x18 + 4 * ((u32)(0xF & (tempData >> 16)))));
    ADC1->ADSTA |= ADC_SR_ADIF;
    puiADData = tempData & 0xfff;
    puiChanData = ChanData & 0xfff;
    if(puiChanData == puiADData)
        return puiADData;
    return 0xFFFF;
}
/// @}


/// @}

/// @}
